using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Unity.VisualScripting;
using UnityEditor.Playables;
using UnityEngine;

namespace  EasyNetWork
{
    public abstract class NetworkChannelBase : INetworkChannel,IDisposable
    {
        private const float DefaultHeartBeatInterval = 30f;

        private readonly string m_Name;
        protected readonly Queue<Packet> m_SendPacketPool;
        protected readonly EventPool<Packet> m_ReceivePacketPool;
        protected readonly INetworkChannelHelper m_NetworkChannelHelper;
        protected AddressFamily m_AddressFamily;
        protected bool m_ResetHeartBeatElapseSecondsWhenReceivePacket;
        protected float m_HeartBeatInterval;
        protected Socket m_Socket;
        protected readonly SendState m_SendState;//发送流
        protected readonly ReceiveState m_ReceiveState; //接收流
        protected readonly HeartBeatState m_HeartBeatState;
        protected int m_SentPacketCount;
        protected int m_ReceivedPacketCount;
        protected bool m_Active;
        private bool m_Disposed;

        public Action<NetworkChannelBase, object> NetworkChannelConnected;
        public Action<NetworkChannelBase> NetworkChannelClosed;
        public Action<NetworkChannelBase, int> NetworkChannelMissHeartBeat;
        public Action<NetworkChannelBase, NetworkErrorCode, SocketError, string> NetworkChannelError;
        public Action<NetworkChannelBase, object> NetworkChannelCustomError;
        
        
        /// <summary>
        /// 初始化网络频道基类的新实例。
        /// </summary>
        /// <param name="name">网络频道名称。</param>
        /// <param name="networkChannelHelper">网络频道辅助器。</param>
        public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
        {
            m_Name = name ?? string.Empty;
            m_SendPacketPool = new Queue<Packet>();
            m_ReceivePacketPool = new EventPool<Packet>(EventPoolMode.Default);
            m_NetworkChannelHelper = networkChannelHelper;
            m_AddressFamily = AddressFamily.Unknown;
            m_ResetHeartBeatElapseSecondsWhenReceivePacket = false;
            m_HeartBeatInterval = DefaultHeartBeatInterval;
            m_Socket = null;
            m_SendState = new SendState();
            m_ReceiveState = new ReceiveState();
            m_HeartBeatState = new HeartBeatState();
            m_SentPacketCount = 0;
            m_ReceivedPacketCount = 0;
            m_Active = false;
            m_Disposed = false;

            NetworkChannelConnected = null;
            NetworkChannelClosed = null;
            NetworkChannelMissHeartBeat = null;
            NetworkChannelError = null;
            NetworkChannelCustomError = null;

            networkChannelHelper.Initialize(this);
        }
        
        /// <summary>
        /// 获取网络频道名称。
        /// </summary>
        public string Name
        {
            get
            {
                return m_Name;
            }
        }
        
        /// <summary>
        /// 获取网络频道所使用的 Socket。
        /// </summary>
        public Socket Socket
        {
            get
            {
                return m_Socket;
            }
        }
        
        /// <summary>
        /// 获取是否已连接。
        /// </summary>
        public bool Connected
        {
            get
            {
                if (m_Socket != null)
                {
                    return m_Socket.Connected;
                }

                return false;
            }
        }
        
        /// <summary>
        /// 获取网络服务类型。
        /// </summary>
        public abstract ServiceType ServiceType
        {
            get;
        }
        
        /// <summary>
        /// 获取网络地址类型。
        /// </summary>
        public AddressFamily AddressFamily
        {
            get
            {
                return m_AddressFamily;
            }
        }
        
        // <summary>
        /// 获取要发送的消息包数量。
        /// </summary>
        public int SendPacketCount
        {
            get
            {
                return m_SendPacketPool.Count;
            }
        }

        /// <summary>
        /// 获取累计发送的消息包数量。
        /// </summary>
        public int SentPacketCount
        {
            get
            {
                return m_SentPacketCount;
            }
        }

        /// <summary>
        /// 获取已接收未处理的消息包数量。
        /// </summary>
        public int ReceivePacketCount
        {
            get
            {
                return m_ReceivePacketPool.EventCount;
            }
        }
        
        /// <summary>
        /// 获取累计已接收的消息包数量。
        /// </summary>
        public int ReceivedPacketCount
        {
            get
            {
                return m_ReceivedPacketCount;
            }
        }

        /// <summary>
        /// 获取或设置当收到消息包时是否重置心跳流逝时间。
        /// </summary>
        public bool ResetHeartBeatElapseSecondsWhenReceivePacket
        {
            get
            {
                return m_ResetHeartBeatElapseSecondsWhenReceivePacket;
            }
            set
            {
                m_ResetHeartBeatElapseSecondsWhenReceivePacket = value;
            }
        }

        /// <summary>
        /// 获取丢失心跳的次数。
        /// </summary>
        public int MissHeartBeatCount
        {
            get
            {
                return m_HeartBeatState.MissHeartBeatCount;
            }
        }

        /// <summary>
        /// 获取或设置心跳间隔时长，以秒为单位。
        /// </summary>
        public float HeartBeatInterval
        {
            get
            {
                return m_HeartBeatInterval;
            }
            set
            {
                m_HeartBeatInterval = value;
            }
        }
        
        /// <summary>
        /// 获取心跳等待时长，以秒为单位。
        /// </summary>
        public float HeartBeatElapseSeconds
        {
            get
            {
                return m_HeartBeatState.HeartBeatElapseSeconds;
            }
        }
        
        /// <summary>
        /// 网络频道轮询
        /// </summary>
        public virtual void Update()
        {
            if (m_Socket == null || !m_Active)
            {
                return;
            }
            ProcessSend();
            ProcessReceive();
            if (m_Socket == null || !m_Active)
            {
                return;
            }
            m_ReceivePacketPool.Update();
            //Time.deltaTime, Time.unscaledDeltaTime
            if (m_HeartBeatInterval > 0f)
            {
                bool sendHeartBeat = false;
                int missHeartBeatCount = 0;
                lock (m_HeartBeatState)
                {
                    if (m_Socket == null || !m_Active)
                    {
                        return;
                    }

                    m_HeartBeatState.HeartBeatElapseSeconds += Time.unscaledDeltaTime;
                    if (m_HeartBeatState.HeartBeatElapseSeconds >= m_HeartBeatInterval)
                    {
                        sendHeartBeat = true;
                        missHeartBeatCount = m_HeartBeatState.MissHeartBeatCount;
                        m_HeartBeatState.HeartBeatElapseSeconds = 0f;
                        m_HeartBeatState.MissHeartBeatCount++;
                    }
                }
                
                //发送心跳包
                if (sendHeartBeat && m_NetworkChannelHelper.SendHeartBeat())
                {
                    if (missHeartBeatCount > 0 && NetworkChannelMissHeartBeat != null)
                    {
                        NetworkChannelMissHeartBeat(this, missHeartBeatCount);
                    }
                }
            }

        }
        
        /// <summary>
        /// 关闭网络频道
        /// </summary>
        public virtual void ShutDown()
        {
            Close();
            m_ReceivePacketPool.ShutDown();
            m_NetworkChannelHelper.Shutdown();
        }
        
        /// <summary>
        /// 注册网络消息包处理函数
        /// </summary>
        /// <param name="handler"></param>
        /// <exception cref="Exception"></exception>
        public void RegisterHandler(IPacketHandler handler)
        {
            if (handler == null)
            {
                throw new System.Exception("PacketHandler无效");
            }
            
            m_ReceivePacketPool.Subscribe(handler.Id,handler.Handle);
        }
        
        /// <summary>
        /// 设置默认处理函数
        /// </summary>
        /// <param name="handler"></param>
        public void SetDefaultHandler(EventHandler<Packet> handler)
        {
            m_ReceivePacketPool.SerDefaultHandler(handler);
        }
        
        /// <summary>
        /// 连接到远程主机
        /// </summary>
        public void Connect(IPAddress ipAddress,int port)
        {
            Connect(ipAddress, port, null);
        }
        
        /// <summary>
        /// 连接到远程主机
        /// 由于连接方式的不同，这里只做一些必要处理，真正的连接有具体实现类负责
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <param name="userdata">用户自定义数据</param>
        /// <exception cref="Exception"></exception>
        public virtual void Connect(IPAddress ipAddress,int port,object userdata)
        {
            if (m_Socket != null)
            {
                Close();
                m_Socket = null;
            }

            switch (ipAddress.AddressFamily)
            {
                case System.Net.Sockets.AddressFamily.InterNetwork:
                    m_AddressFamily = AddressFamily.IPv4;
                    break;
                case System.Net.Sockets.AddressFamily.InterNetworkV6:
                    m_AddressFamily = AddressFamily.IPv6;
                    break;
                default:
                    string errorMessage = $"无支持的地址族";
                    if (NetworkChannelError != null)
                    {
                        NetworkChannelError(this, NetworkErrorCode.AddressFamilyError, SocketError.Success,
                            errorMessage);
                        return;
                    }

                    throw new System.Exception(errorMessage);
            }
            //重置发送流和接收流
            m_SendState.Reset();
            m_ReceiveState.PrepareForPacketHeader(m_NetworkChannelHelper.PacketHeaderLength);
        }
        
        /// <summary>
        /// 关闭连接并释放所有相关资源。
        /// </summary>
        public void Close()
        {
            lock (this)
            {
                if (m_Socket == null)
                {
                    return;
                }

                m_Active = false;

                try
                {
                    m_Socket.Shutdown(SocketShutdown.Both);
                }
                catch
                {
                }
                finally
                {
                    m_Socket.Close();
                    m_Socket = null;

                    if (NetworkChannelClosed != null)
                    {
                        NetworkChannelClosed(this);
                    }
                }

                m_SentPacketCount = 0;
                m_ReceivedPacketCount = 0;

                lock (m_SendPacketPool)
                {
                    m_SendPacketPool.Clear();
                }

                m_ReceivePacketPool.Clear();

                lock (m_HeartBeatState)
                {
                    m_HeartBeatState.Reset(true);
                }
            }
        }
        
        /// <summary>
        /// 向远程主机发送消息包。
        /// </summary>
        /// <typeparam name="T">消息包类型。</typeparam>
        /// <param name="packet">要发送的消息包。</param>
        public void Send<T>(T packet) where T : Packet
        {
            if (m_Socket == null)
            {
                string errorMessage = "你必须先连接";
                if (NetworkChannelError != null)
                {
                    NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
                    return;
                }

                throw new System.Exception(errorMessage);
            }

            if (!m_Active)
            {
                string errorMessage = "Socket未开启";
                if (NetworkChannelError != null)
                {
                    NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
                    return;
                }

                throw new System.Exception(errorMessage);
            }

            if (packet == null)
            {
                string errorMessage = "数据包无效";
                if (NetworkChannelError != null)
                {
                    NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
                    return;
                }

                throw new System.Exception(errorMessage);
            }

            lock (m_SendPacketPool)
            {
                m_SendPacketPool.Enqueue(packet);
            }
        }
        
        /// <summary>
        /// 释放资源。
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        
        /// <summary>
        /// 释放资源。
        /// </summary>
        /// <param name="disposing">释放资源标记。</param>
        private void Dispose(bool disposing)
        {
            if (m_Disposed)
            {
                return;
            }

            if (disposing)
            {
                Close();
                m_SendState.Dispose();
                m_ReceiveState.Dispose();
            }

            m_Disposed = true;
        }

        protected virtual bool ProcessSend()
        {
            if (m_SendState.Stream.Length >0 || m_SendPacketPool.Count<= 0)
            {
                return false;
            }

            while (m_SendPacketPool.Count > 0)
            {
                Packet packet = null;
                //从SendPacket池中取出
                lock (m_SendPacketPool)
                {
                    packet = m_SendPacketPool.Dequeue();
                }
                

                bool serializeResult = false;
                //序列化并写入m_SendState包中
                try
                {
                    serializeResult = m_NetworkChannelHelper.Serialize(packet, m_SendState.Stream);
                }
                catch(Exception exception)
                {
                    m_Active = false;
                    if (NetworkChannelError != null)
                    {
                        SocketException socketException = exception as SocketException;
                        NetworkChannelError(this, NetworkErrorCode.SerializeError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
                        return false;
                    }

                    throw;
                }

                if (!serializeResult)
                {
                    string errorMessage = "序列化包失败";
                    if (NetworkChannelError != null)
                    {
                       NetworkChannelError(this, NetworkErrorCode.SerializeError, SocketError.Success, errorMessage);
                       return false;
                    }

                    throw new System.Exception(errorMessage);
                }
            }
            m_SendState.Stream.Position = 0L;
            return true;
        }
        
        protected virtual void ProcessReceive()
        {
        }
        
         protected virtual bool ProcessPacketHeader()
        {
            try
            {
                object customErrorData = null;
                //反序列换包头
                IPacketHeader packetHeader = m_NetworkChannelHelper.DeserializePacketHeader(m_ReceiveState.Stream, out customErrorData);

                if (customErrorData != null && NetworkChannelCustomError != null)
                {
                    NetworkChannelCustomError(this, customErrorData);
                }

                if (packetHeader == null)
                {
                    string errorMessage = "包头无效";
                    if (NetworkChannelError != null)
                    {
                        NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, SocketError.Success, errorMessage);
                        return false;
                    }

                    throw new System.Exception(errorMessage);
                }
                //接收流准备接收数据包
                m_ReceiveState.PrepareForPacket(packetHeader); //将包头参数带入接收流程中，以此准备接下来的数据包解析
                if (packetHeader.PacketLength <= 0)
                {
                    bool processSuccess = ProcessPacket();//解析数据包
                    m_ReceivedPacketCount++;
                    return processSuccess;
                }
            }
            catch (Exception exception)
            {
                m_Active = false;
                if (NetworkChannelError != null)
                {
                    SocketException socketException = exception as SocketException;
                    NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
                    return false;
                }

                throw;
            }

            return true;
        }
         
         /// <summary>
         /// 包流程
         /// </summary>
         /// <returns></returns>
         protected virtual bool ProcessPacket()
         {
             //重置心跳流
             lock (m_HeartBeatState)
             {
                 m_HeartBeatState.Reset(m_ResetHeartBeatElapseSecondsWhenReceivePacket);
             }

             try
             {
                 object customErrorData = null;
                 //反序列化数据包，包头是用的上一步中接收流程先解出的包头
                 Packet packet = m_NetworkChannelHelper.DeserializePacket(m_ReceiveState.PacketHeader, m_ReceiveState.Stream, out customErrorData);

                 if (customErrorData != null && NetworkChannelCustomError != null)
                 {
                     NetworkChannelCustomError(this, customErrorData);
                 }
                 //这里数据包如果不为空，说明有数据，把这个数据推到事件池中，由事件池触发事件
                 if (packet != null)
                 {
                     m_ReceivePacketPool.Fire(this, packet);
                 }
                 //到这里就是一个完整的数据包解析并发送事件，然后重置接收流程中的包头，以此来让接收流程准备接收下一个数据包
                 m_ReceiveState.PrepareForPacketHeader(m_NetworkChannelHelper.PacketHeaderLength);
             }
             catch (Exception exception)
             {
                 m_Active = false;
                 if (NetworkChannelError != null)
                 {
                     SocketException socketException = exception as SocketException;
                     NetworkChannelError(this, NetworkErrorCode.DeserializePacketError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
                     return false;
                 }

                 throw;
             }

             return true;
         }

    }

}
